import sys
import io
import threading
import traceback
import pdb
import bdb
import types
import tempfile
import os
from contextlib import redirect_stdout, redirect_stderr

class WebPdbDebugger(bdb.Bdb):
    """基于官方pdb的Web调试器"""
    
    def __init__(self, code, socketio=None):
        super().__init__()
        self.code = code
        self.socketio = socketio
        self.lines = code.strip().split('\n')
        self.current_line = 0
        self.current_frame = None
        self.variables = {}
        self.breakpoints = set()
        self.is_running = False
        self.is_finished = False
        self.output_buffer = io.StringIO()
        self.error_buffer = io.StringIO()
        self.execution_thread = None
        self.step_event = threading.Event()
        self.continue_event = threading.Event()
        self.stop_event = threading.Event()
        self.waiting_for_input = False
        
        # 添加执行模式控制
        self.step_mode = True  # True: 单步模式, False: 继续执行模式
        self.should_stop = False  # 是否应该在当前行停下
        
        # 创建临时文件来存储代码
        self.temp_file = tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False)
        self.temp_file.write(self.code)
        self.temp_file.close()
        self.filename = self.temp_file.name
        
        # 编译代码检查语法
        try:
            compile(self.code, self.filename, 'exec')
        except SyntaxError as e:
            os.unlink(self.filename)
            raise Exception(f"Syntax error in code: {e}")
    
    def __del__(self):
        """清理临时文件"""
        try:
            if hasattr(self, 'filename') and os.path.exists(self.filename):
                os.unlink(self.filename)
        except:
            pass
    
    def start(self):
        """启动调试器"""
        if self.is_running:
            return {'error': 'Debugger is already running'}
        
        self.is_running = True
        self.is_finished = False
        self.current_line = 1
        self.variables = {}
        self.step_mode = True  # 启动时默认为单步模式
        
        # 设置断点
        for bp_line in self.breakpoints:
            self.set_break(self.filename, bp_line)
        
        # 在新线程中执行代码
        self.execution_thread = threading.Thread(target=self._execute_with_debug)
        self.execution_thread.daemon = True
        self.execution_thread.start()
        
        return {
            'status': 'started',
            'current_line': self.current_line,
            'total_lines': len(self.lines)
        }
    
    def step(self):
        """单步执行"""
        if not self.is_running or self.is_finished:
            return {'error': 'No active debugging session'}
        
        if self.waiting_for_input:
            self.step_mode = True  # 设置为单步模式
            self.continue_event.clear()  # 清除继续执行标志
            # 触发单步执行
            self.step_event.set()
        
        return self._get_current_state()
    
    def continue_execution(self):
        """继续执行直到下一个断点或结束"""
        if not self.is_running or self.is_finished:
            return {'error': 'No active debugging session'}
        
        if self.waiting_for_input:
            self.step_mode = False  # 设置为继续执行模式
            # 触发继续执行
            self.continue_event.set()
        
        return self._get_current_state()
    
    def set_breakpoint(self, line_number):
        """设置断点"""
        if 1 <= line_number <= len(self.lines):
            self.breakpoints.add(line_number)
            if self.is_running:
                self.set_break(self.filename, line_number)
            return {
                'status': 'success',
                'message': f'Breakpoint set at line {line_number}',
                'breakpoints': list(self.breakpoints)
            }
        else:
            return {'error': f'Invalid line number: {line_number}'}
    
    def remove_breakpoint(self, line_number):
        """移除断点"""
        if line_number in self.breakpoints:
            self.breakpoints.remove(line_number)
            if self.is_running:
                self.clear_break(self.filename, line_number)
            return {
                'status': 'success',
                'message': f'Breakpoint removed from line {line_number}',
                'breakpoints': list(self.breakpoints)
            }
        else:
            return {'error': f'No breakpoint at line {line_number}'}
    
    def get_variables(self):
        """获取当前变量状态"""
        return self._format_variables(self.variables)
    
    def stop(self):
        """停止调试器"""
        self.is_running = False
        self.stop_event.set()
        self.set_quit()
        if self.execution_thread and self.execution_thread.is_alive():
            self.execution_thread.join(timeout=1.0)
    
    # pdb回调方法
    def user_line(self, frame):
        """当执行到用户代码行时调用"""
        if self.stop_event.is_set():
            self.set_quit()
            return
        
        self.current_frame = frame
        self.current_line = frame.f_lineno
        self._update_variables(frame)
        
        # 判断是否应该停下来
        should_pause = False
        
        if self.step_mode:
            # 单步模式：每行都停
            should_pause = True
        else:
            # 继续执行模式：只在断点处停
            if self.current_line in self.breakpoints:
                should_pause = True
                # 遇到断点后，切换回单步模式
                self.step_mode = True
                self.continue_event.clear()
        
        # 发送状态更新
        self._emit_state_update()
        
        if should_pause:
            # 等待用户操作
            self.waiting_for_input = True
            self._wait_for_user_action()
            self.waiting_for_input = False
    
    def user_return(self, frame, return_value):
        """当从用户函数返回时调用"""
        if self.stop_event.is_set():
            self.set_quit()
            return
        
        self.current_frame = frame
        self.current_line = frame.f_lineno
        self._update_variables(frame)
        
        # 如果有返回值，添加到变量中
        if return_value is not None:
            self.variables['<return_value>'] = return_value
        
        self._emit_state_update()
        
        # 函数返回时，如果是单步模式也要暂停
        if self.step_mode:
            self.waiting_for_input = True
            self._wait_for_user_action()
            self.waiting_for_input = False
    
    def user_exception(self, frame, exc_info):
        """当发生异常时调用"""
        exc_type, exc_value, exc_traceback = exc_info
        error_msg = f"Exception at line {frame.f_lineno}: {exc_type.__name__}: {exc_value}"
        self.error_buffer.write(error_msg + '\n')
        
        if self.socketio:
            self.socketio.emit('error', {
                'message': error_msg,
                'line': frame.f_lineno,
                'type': exc_type.__name__,
                'value': str(exc_value)
            })
        
        self.current_frame = frame
        self.current_line = frame.f_lineno
        self._update_variables(frame)
        self._emit_state_update()
        
        # 异常时总是暂停，并切换到单步模式
        self.step_mode = True
        self.continue_event.clear()
        self.waiting_for_input = True
        self._wait_for_user_action()
        self.waiting_for_input = False
    
    def _execute_with_debug(self):
        """在调试模式下执行代码"""
        try:
            # 创建执行环境
            global_vars = {
                '__builtins__': __builtins__,
                '__name__': '__main__',
                '__doc__': None,
                '__package__': None,
                '__file__': self.filename
            }
            
            # 捕获输出
            with redirect_stdout(self.output_buffer), redirect_stderr(self.error_buffer):
                # 使用pdb运行代码
                self.run(compile(self.code, self.filename, 'exec'), global_vars)
            
            self.is_finished = True
            self._emit_state_update()
            
        except SystemExit:
            # 正常退出
            self.is_finished = True
            self._emit_state_update()
        except Exception as e:
            error_msg = f"Execution error: {str(e)}"
            self.error_buffer.write(error_msg + '\n')
            if self.socketio:
                self.socketio.emit('error', {'message': error_msg})
            self.is_finished = True
            self._emit_state_update()
    
    def _update_variables(self, frame):
        """更新变量信息"""
        if frame:
            # 合并局部变量和全局变量
            self.variables = {}
            
            # 局部变量
            if frame.f_locals:
                for name, value in frame.f_locals.items():
                    if not name.startswith('__'):
                        self.variables[f"(local) {name}"] = value
            
            # 全局变量
            if frame.f_globals:
                for name, value in frame.f_globals.items():
                    if not name.startswith('__') and name not in ['__builtins__']:
                        # 避免重复显示局部变量
                        if f"(local) {name}" not in self.variables:
                            self.variables[f"(global) {name}"] = value
    
    def _wait_for_user_action(self):
        """等待用户操作（单步或继续）"""
        while self.is_running and not self.stop_event.is_set():
            if self.step_event.wait(timeout=0.1):
                self.step_event.clear()
                break
            if self.continue_event.is_set():
                break
    
    def _get_current_state(self):
        """获取当前调试状态"""
        return {
            'current_line': self.current_line,
            'total_lines': len(self.lines),
            'variables': self._format_variables(self.variables),
            'breakpoints': list(self.breakpoints),
            'is_finished': self.is_finished,
            'output': self.output_buffer.getvalue(),
            'errors': self.error_buffer.getvalue(),
            'step_mode': self.step_mode  # 添加执行模式信息
        }
    
    def _format_variables(self, variables):
        """格式化变量信息"""
        formatted = {}
        for name, value in variables.items():
            try:
                # 限制字符串长度，避免显示过长的内容
                str_value = str(value)
                if len(str_value) > 200:
                    str_value = str_value[:200] + "..."
                
                repr_value = repr(value)
                if len(repr_value) > 200:
                    repr_value = repr_value[:200] + "..."
                
                formatted[name] = {
                    'value': str_value,
                    'type': type(value).__name__,
                    'repr': repr_value
                }
            except:
                formatted[name] = {
                    'value': '<unable to display>',
                    'type': type(value).__name__,
                    'repr': '<unable to display>'
                }
        return formatted
    
    def _emit_state_update(self):
        """向前端发送状态更新"""
        if self.socketio:
            state = self._get_current_state()
            self.socketio.emit('state_update', state)


# 为了保持向后兼容，创建一个别名
class PythonDebugger(WebPdbDebugger):
    """向后兼容的别名"""
    pass 